package com.imhouxy.springTemplateQuery.query;

import lombok.extern.slf4j.Slf4j;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;

@Slf4j
public abstract class AbstractQuery<T> {

    @Resource
    private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
    private final RowMapper<T> mapper;

    public AbstractQuery(Class<T> tClass) {
        this.mapper = new BeanPropertyRowMapper<>(tClass);
    }

    public AbstractQuery(RowMapper<T> mapper) {
        this.mapper = mapper;
    }


    protected abstract String viewSql();

    private String querySql(QueryWrapper wrapper) {
        String sql = "select * from (" + this.viewSql() + ") view ";
        String where = wrapper.sqlFragment();
        if (!StringUtils.isEmpty(where)) {
            sql = sql + " where " + where;
        }
        String orderBy = wrapper.getOrderBy();
        if (!StringUtils.isEmpty(orderBy)) {
            sql = sql + " order by " + orderBy;
        }
        return sql;
    }

    private String countSql(QueryWrapper wrapper) {
        String sql = "select count(1) from (" + this.viewSql() + ") view ";
        String where = wrapper.sqlFragment();
        if (StringUtils.isEmpty(where)) {
            return sql;
        }
        return sql + " where " + where;
    }

    public T selectOne(QueryWrapper wrapper) {
        String sql = querySql(wrapper);
        Map<String, Object> param = wrapper.param();
        sql = sql + " limit 1";
        List<T> list = namedParameterJdbcTemplate.query(sql, param, mapper);
        if (CollectionUtils.isEmpty(list)) {
            return null;
        }
        return list.get(0);
    }

    public List<T> selectList(QueryWrapper wrapper) {
        String sql = querySql(wrapper);
        Map<String, Object> param = wrapper.param();
        return namedParameterJdbcTemplate.query(sql, param, mapper);
    }

    public long selectCount(QueryWrapper wrapper) {
        String sql = countSql(wrapper);
        Long count = namedParameterJdbcTemplate.queryForObject(sql, wrapper.param(), Long.class);
        if (count == null) {
            return 0;
        }
        return count;
    }

    public PageResult<T> selectPage(QueryWrapper wrapper) {
        String sql = querySql(wrapper);
        Map<String, Object> param = wrapper.param();
        long curPage = wrapper.getCurPage() - 1;
        if (curPage < 0) {
            curPage = 0;
        }
        long start = curPage * wrapper.getPageSize();
        sql += " limit " + start + "," + wrapper.getPageSize();
        List<T> list = namedParameterJdbcTemplate.query(sql, param, mapper);
        long count = this.selectCount(wrapper);
        PageResult<T> result = new PageResult<>();
        result.setList(list);
        result.setRowCount(count);
        return result;
    }
}
